/*
 * SoapUI, Copyright (C) 2004-2017 SmartBear Software
 *
 * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent 
 * versions of the EUPL (the "Licence"); 
 * You may not use this work except in compliance with the Licence. 
 * You may obtain a copy of the Licence at: 
 * 
 * http://ec.europa.eu/idabc/eupl 
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the Licence is 
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
 * express or implied. See the Licence for the specific language governing permissions and limitations 
 * under the Licence. 
 */

package com.eviware.soapui.impl.wsdl.panels.teststeps.support;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.rest.support.RestParameter;
import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
import com.eviware.soapui.impl.wsdl.MutableTestPropertyHolder;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.PathUtils;
import com.eviware.soapui.impl.wsdl.teststeps.AMFRequestTestStep;
import com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep;
import com.eviware.soapui.model.TestPropertyHolder;
import com.eviware.soapui.model.environment.Environment;
import com.eviware.soapui.model.environment.EnvironmentListener;
import com.eviware.soapui.model.iface.Interface;
import com.eviware.soapui.model.mock.MockService;
import com.eviware.soapui.model.project.Project;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionImpl;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.support.ProjectListenerAdapter;
import com.eviware.soapui.model.support.TestPropertyUtils;
import com.eviware.soapui.model.testsuite.TestProperty;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.model.tree.nodes.PropertyTreeNode.PropertyModelItem;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.swing.JTableFactory;
import com.eviware.soapui.support.xml.XmlUtils;
import com.eviware.x.form.XFormDialog;
import com.eviware.x.form.support.ADialogBuilder;
import com.eviware.x.form.support.AField;
import com.eviware.x.form.support.AField.AFieldType;
import com.eviware.x.form.support.AForm;
import com.eviware.x.impl.swing.FileFormField;
import org.apache.commons.io.FilenameUtils;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@SuppressWarnings("serial")
public class PropertyHolderTable extends JPanel {
    public static final String PROPERTIES_HOLDER_TABLE_NAME = "PropertiesHolderTable";
    protected final TestPropertyHolder holder;
    protected DefaultPropertyHolderTableModel propertiesModel;
    protected RemovePropertyAction removePropertyAction;
    protected AddParamAction addPropertyAction;
    protected JTable propertiesTable;
    protected JXToolBar toolbar;
    protected LoadPropertiesAction loadPropertiesAction;
    protected MovePropertyUpAction movePropertyUpAction;
    protected MovePropertyDownAction movePropertyDownAction;
    private EnvironmentListener environmentListener;
    private ProjectListenerAdapter projectListener;

    public PropertyHolderTable(TestPropertyHolder holder) {
        super(new BorderLayout());
        this.holder = holder;

        loadPropertiesAction = new LoadPropertiesAction();
        JScrollPane scrollPane = new JScrollPane(buildPropertiesTable());

        if (getHolder().getModelItem() != null) {
            DropTarget dropTarget = new DropTarget(scrollPane, new PropertyHolderTablePropertyExpansionDropTarget());
            dropTarget.setDefaultActions(DnDConstants.ACTION_COPY_OR_MOVE);
        }

        add(scrollPane, BorderLayout.CENTER);
        add(buildToolbar(), BorderLayout.NORTH);

        projectListener = new ProjectListenerAdapter() {
            public void environmentSwitched(Environment environment) {
                getPropertiesModel().fireTableDataChanged();
            }
        };
    }

    protected JTable buildPropertiesTable() {
        propertiesModel = getPropertyHolderTableModel();
        propertiesTable = new PropertiesHolderJTable();
        propertiesTable.setName(PROPERTIES_HOLDER_TABLE_NAME);
        propertiesTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
        propertiesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                int selectedRow = propertiesTable.getSelectedRow();
                if (removePropertyAction != null) {
                    removePropertyAction.setEnabled(selectedRow != -1);
                }

                if (movePropertyUpAction != null) {
                    movePropertyUpAction.setEnabled(selectedRow > 0);
                }

                if (movePropertyDownAction != null) {
                    movePropertyDownAction.setEnabled(selectedRow >= 0 && selectedRow < propertiesTable.getRowCount() - 1);
                }
            }
        });

        propertiesTable.setDragEnabled(true);
        propertiesTable.setTransferHandler(new TransferHandler("testProperty"));

        if (getHolder().getModelItem() != null) {
            DropTarget dropTarget = new DropTarget(propertiesTable, new PropertyHolderTablePropertyExpansionDropTarget());
            dropTarget.setDefaultActions(DnDConstants.ACTION_COPY_OR_MOVE);
        }

        // Set render this only for value column. In this cell render we handle password shadowing.
        propertiesTable.getColumnModel().getColumn(1).setCellRenderer(new PropertiesTableCellRenderer());
        return propertiesTable;
    }

    protected DefaultPropertyHolderTableModel getPropertyHolderTableModel() {
        return new DefaultPropertyHolderTableModel(holder);
    }

    public class PropertiesHolderJTable extends JTable {
        public PropertiesHolderJTable() {
            super(propertiesModel);
            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            setSurrendersFocusOnKeystroke(true);
            setRowHeight(19);
            if (UISupport.isMac()) {
                setShowGrid(false);
                setIntercellSpacing(new Dimension(0, 0));
            }
        }

        @Override
        public void removeEditor() {
            TableCellEditor editor = getCellEditor();
            // must be called here to remove the editor and to avoid an infinite
            // loop, because the table is an editor listener and the
            // editingCanceled method calls this removeEditor method
            super.removeEditor();
            if (editor != null) {
                editor.cancelCellEditing();
            }
        }

        public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
            Component defaultRenderer = super.prepareRenderer(renderer, row, column);
            if (UISupport.isMac()) {
                JTableFactory.applyStripesToRenderer(row, defaultRenderer);
            }
            return defaultRenderer;
        }

        @Override
        public boolean getShowVerticalLines() {
            return !UISupport.isMac();
        }

        public PropertyModelItem getTestProperty() {
            int index = getSelectedRow();
            if (index == -1) {
                return null;
            }
            TestProperty property = propertiesModel.getPropertyAtRow(index);
            return new PropertyModelItem(property, true);
        }
    }

    private Component buildToolbar() {
        toolbar = UISupport.createSmallToolbar();

        if (holder instanceof MutableTestPropertyHolder) {
            removePropertyAction = new RemovePropertyAction();
            MutableTestPropertyHolder mutablePropertyHolder = (MutableTestPropertyHolder) holder;
            addPropertyAction = new AddParamAction(propertiesTable, mutablePropertyHolder, "Adds a property to the property list");
            movePropertyUpAction = new MovePropertyUpAction(propertiesTable, mutablePropertyHolder,
                    "Moves selected property up one row");
            movePropertyDownAction = new MovePropertyDownAction(propertiesTable, mutablePropertyHolder,
                    "Moves selected property down one row");

            JButton addPropertyButton = UISupport.createToolbarButton(addPropertyAction);
            toolbar.add(addPropertyButton);
            JButton removePropertyButton = UISupport.createToolbarButton(removePropertyAction);
            toolbar.add(removePropertyButton);

            toolbar.addRelatedGap();
            JButton movePropertyUpButton = UISupport.createToolbarButton(movePropertyUpAction);
            toolbar.add(movePropertyUpButton);
            JButton movePropertyDownButton = UISupport.createToolbarButton(movePropertyDownAction);
            toolbar.add(movePropertyDownButton);

            if (!(holder instanceof AMFRequestTestStep || holder instanceof JdbcRequestTestStep)) {
                toolbar.addRelatedGap();
                toolbar.add(UISupport.createToolbarButton(new SortPropertiesAction()));
                toolbar.addRelatedGap();
            }
        }

        JButton clearPropertiesButton = UISupport.createToolbarButton(new ClearPropertiesAction());
        toolbar.add(clearPropertiesButton);
        JButton loadPropertiesButton = UISupport.createToolbarButton(loadPropertiesAction);
        toolbar.add(loadPropertiesButton);
        toolbar.add(UISupport.createToolbarButton(new SavePropertiesAction()));

        return toolbar;
    }

    public JXToolBar getToolbar() {
        return toolbar;
    }

    public JTable getPropertiesTable() {
        return propertiesTable;
    }

    public void release() {
        if (propertiesTable.isEditing()) {
            propertiesTable.getCellEditor().stopCellEditing();
        }

        propertiesModel.release();

        if (holder instanceof WsdlProject) {
            WsdlProject project = (WsdlProject) holder;
            project.removeEnvironmentListener(environmentListener);
            project.removeProjectListener(projectListener);
        }

        projectListener = null;
    }

    public void setEnabled(boolean enabled) {
        addPropertyAction.setEnabled(enabled);
        removePropertyAction.setEnabled(enabled);
        propertiesTable.setEnabled(enabled);
        loadPropertiesAction.setEnabled(enabled);

        super.setEnabled(enabled);
    }

    protected class RemovePropertyAction extends AbstractAction {
        public RemovePropertyAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/delete.png"));
            putValue(Action.SHORT_DESCRIPTION, "Removes the selected property from the property list");
            setEnabled(false);
        }

        public void actionPerformed(ActionEvent e) {
            int row = propertiesTable.getSelectedRow();
            if (row == -1) {
                return;
            }

            UISupport.stopCellEditing(propertiesTable);

            String propertyName = propertiesModel.getValueAt(row, 0).toString();
            if (UISupport.confirm("Remove property [" + propertyName + "]?", "Remove Property")) {
                ((MutableTestPropertyHolder) holder).removeProperty(propertyName);
                propertiesModel.fireTableRowsDeleted(row, row);
            }
        }
    }

    protected class ClearPropertiesAction extends AbstractAction {
        public ClearPropertiesAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/clear.png"));
            putValue(Action.SHORT_DESCRIPTION, "Clears all current property values");
        }

        public void actionPerformed(ActionEvent e) {
            if (UISupport.confirm("Clear all property values?", "Clear Properties")) {
                for (String name : holder.getPropertyNames()) {
                    TestProperty property = holder.getProperty(name);
                    property.setValue(null);
                    if (property instanceof RestParameter) {
                        ((RestParameter) property).setDefaultValue(null);
                    }
                }
            }
        }
    }

    protected class LoadPropertiesAction extends AbstractAction {
        private XFormDialog dialog;

        public LoadPropertiesAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/load_properties.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Loads property values from an external file");
        }

        public void actionPerformed(ActionEvent e) {
            if (dialog == null) {
                dialog = ADialogBuilder.buildDialog(LoadOptionsForm.class);
            }

            Project project = ModelSupport.getModelItemProject(holder.getModelItem());
            if (project != null) {
                FileFormField fileFormField = (FileFormField) dialog.getFormField(LoadOptionsForm.FILE);
                String currentDirectory = extractFileChooserPathForProject(project);
                fileFormField.setCurrentDirectory(currentDirectory);
            }

            dialog.getFormField(LoadOptionsForm.DELETEREMAINING)
                    .setEnabled(holder instanceof MutableTestPropertyHolder);
            dialog.getFormField(LoadOptionsForm.CREATEMISSING).setEnabled(holder instanceof MutableTestPropertyHolder);

            if (dialog.show()) {
                try {
                    BufferedReader reader = new BufferedReader(new FileReader(dialog.getValue(LoadOptionsForm.FILE)));

                    String line = reader.readLine();
                    int count = 0;

                    Set<String> names = new HashSet<String>(Arrays.asList(holder.getPropertyNames()));

                    while (line != null) {
                        if (line.trim().length() > 0 && !(line.charAt(0) == '#')) {
                            int ix = line.indexOf('=');
                            if (ix > 0) {
                                String name = line.substring(0, ix).trim();
                                String value = line.length() > ix ? line.substring(ix + 1) : "";

                                // read multiline value
                                if (value.endsWith("\\")) {
                                    int slashCount = TestPropertyUtils.countEndingSlashes(value);
                                    if (slashCount % 2 != 0) {
                                        value = value.substring(0, value.length() - ((slashCount + 1) / 2));

                                        String ln = reader.readLine();
                                        while (ln != null && ln.endsWith("\\")) {
                                            int slashCountLn = TestPropertyUtils.countEndingSlashes(ln);
                                            if (slashCountLn % 2 != 0) {
                                                value += ln.substring(0, ln.length() - ((slashCountLn + 1) / 2));
                                                ln = reader.readLine();
                                            } else {
                                                ln = ln.substring(0, ln.length() - (slashCountLn / 2));
                                                break;
                                            }
                                        }
                                        if (ln != null) {
                                            value += ln;
                                        }
                                    } else {
                                        value = value.substring(0, value.length() - (slashCount / 2));
                                    }
                                }

                                if (holder.hasProperty(name)) {
                                    count++;
                                    holder.getProperty(name).setValue(value);
                                    holder.setPropertyValue(name, value);
                                } else if (dialog.getBooleanValue(LoadOptionsForm.CREATEMISSING)
                                        && holder instanceof MutableTestPropertyHolder) {
                                    TestProperty prop = ((MutableTestPropertyHolder) holder).addProperty(name);
                                    if (!prop.isReadOnly()) {
                                        prop.setValue(value);
                                        if (prop instanceof RestParameter) {
                                            ((RestParameter) prop).setDefaultValue(value);
                                        }
                                    }
                                    count++;
                                }

                                names.remove(name);
                            }
                        }

                        line = reader.readLine();
                    }

                    if (dialog.getBooleanValue(LoadOptionsForm.DELETEREMAINING)
                            && holder instanceof MutableTestPropertyHolder) {
                        for (String name : names) {
                            ((MutableTestPropertyHolder) holder).removeProperty(name);
                        }
                    }

                    reader.close();
                    UISupport.showInfoMessage("Added/Updated " + count + " properties from file");
                } catch (Exception ex) {
                    UISupport.showErrorMessage(ex);
                }
            }
        }

        private String extractFileChooserPathForProject(Project project) {
            String currentDirectory = determineSuggestedDirectory(project);
            File file = ensurePathExistsAndIsDirectory(currentDirectory);

            return file.getAbsolutePath();
        }

        private String determineSuggestedDirectory(Project project) {
            String currentDirectory = StringUtils.hasContent(project.getResourceRoot()) ? project.getResourceRoot() : project.getPath();
            if (!StringUtils.hasContent(currentDirectory)) {
                return System.getProperty("user.dir", ".");
            } else if (holder.getModelItem() instanceof AbstractWsdlModelItem) {
                String expandedPath = PathUtils.expandPath(currentDirectory, ((AbstractWsdlModelItem) (holder.getModelItem())));
                return FilenameUtils.normalize(expandedPath);
            } else {
                return currentDirectory;
            }
        }

        private File ensurePathExistsAndIsDirectory(String path) {
            File file = new File(path);
            while (!(file == null) && !file.exists()) {
                file = file.getParentFile();
            }
            if (file == null) {
                file = getCurrentJvmDirectory();
            }
            if (!file.isDirectory()) {
                file = file.getParentFile();
            }
            return file;
        }

        private File getCurrentJvmDirectory() {
            return new File(System.getProperty("user.dir", ".")).getAbsoluteFile();
        }
    }

    private class SavePropertiesAction extends AbstractAction {
        public SavePropertiesAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/set_properties_target.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Saves current property-values to a file");
        }

        public void actionPerformed(ActionEvent e) {
            if (holder.getPropertyCount() == 0) {
                UISupport.showErrorMessage("No properties to save!");
                return;
            }

            File file = UISupport.getFileDialogs().saveAs(this, "Save Properties");
            if (file != null) {
                try {
                    int cnt = TestPropertyUtils.saveTo(holder, file.getAbsolutePath());
                    UISupport.showInfoMessage("Saved " + cnt + " propert" + ((cnt == 1) ? "y" : "ies") + " to file");
                } catch (IOException e1) {
                    UISupport.showErrorMessage(e1);
                }
            }
        }
    }

    private class SortPropertiesAction extends AbstractAction {
        public SortPropertiesAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/arrow_down.png"));
            putValue(Action.SHORT_DESCRIPTION, "Sorts properties alphabetically");
        }

        public void actionPerformed(ActionEvent e) {
            if (holder.getPropertyCount() == 0) {
                UISupport.showErrorMessage("No properties to sort!");
                return;
            }

            try {
                UISupport.setHourglassCursor();
                propertiesModel.sort();
            } finally {
                UISupport.resetCursor();
            }

        }
    }

    @AForm(name = "Load Properties", description = "Set load options below")
    private static interface LoadOptionsForm {
        @AField(name = "File", description = "The Properties file to load", type = AFieldType.FILE)
        public static final String FILE = "File";

        @AField(name = "Create Missing", description = "Creates Missing Properties", type = AFieldType.BOOLEAN)
        public static final String CREATEMISSING = "Create Missing";

        @AField(name = "Delete Remaining", description = "Deletes properties not in file", type = AFieldType.BOOLEAN)
        public static final String DELETEREMAINING = "Delete Remaining";
    }

    public TestPropertyHolder getHolder() {
        return holder;
    }

    public PropertyHolderTableModel getPropertiesModel() {
        return propertiesModel;
    }

    public final class PropertyHolderTablePropertyExpansionDropTarget implements DropTargetListener {
        public PropertyHolderTablePropertyExpansionDropTarget() {
        }

        public void dragEnter(DropTargetDragEvent dtde) {
            if (!isAcceptable(dtde.getTransferable(), dtde.getLocation())) {
                dtde.rejectDrag();
            }
        }

        public void dragExit(DropTargetEvent dtde) {
        }

        public void dragOver(DropTargetDragEvent dtde) {
            if (!isAcceptable(dtde.getTransferable(), dtde.getLocation())) {
                dtde.rejectDrag();
            } else {
                dtde.acceptDrag(dtde.getDropAction());
            }
        }

        public void drop(DropTargetDropEvent dtde) {
            if (!isAcceptable(dtde.getTransferable(), dtde.getLocation())) {
                dtde.rejectDrop();
            } else {
                try {
                    Transferable transferable = dtde.getTransferable();
                    Object transferData = transferable.getTransferData(transferable.getTransferDataFlavors()[0]);
                    if (transferData instanceof PropertyModelItem) {
                        dtde.acceptDrop(dtde.getDropAction());
                        PropertyModelItem modelItem = (PropertyModelItem) transferData;

                        String xpath = modelItem.getXPath();
                        if (xpath == null && XmlUtils.seemsToBeXml(modelItem.getProperty().getValue())) {
                            xpath = UISupport.selectXPath("Create PropertyExpansion", "Select XPath below", modelItem
                                    .getProperty().getValue(), null);

                            if (xpath != null) {
                                xpath = PropertyExpansionUtils.shortenXPathForPropertyExpansion(xpath, modelItem.getProperty()
                                        .getValue());
                            }
                        }

                        PropertyExpansion propertyExpansion = new PropertyExpansionImpl(modelItem.getProperty(), xpath);

                        Point point = dtde.getLocation();
                        int column = getPropertiesTable().columnAtPoint(point);
                        int row = getPropertiesTable().rowAtPoint(point);

                        if (row == -1) {
                            if (holder instanceof MutableTestPropertyHolder) {
                                MutableTestPropertyHolder mtph = (MutableTestPropertyHolder) holder;
                                String name = UISupport.prompt("Specify unique name of property", "Add Property", modelItem
                                        .getProperty().getName());
                                while (name != null && mtph.hasProperty(name)) {
                                    name = UISupport.prompt("Specify unique name of property", "Add Property", modelItem
                                            .getProperty().getName());
                                }

                                if (name != null) {
                                    mtph.addProperty(name).setValue(propertyExpansion.toString());
                                }
                            }
                        } else {
                            getPropertiesTable().setValueAt(propertyExpansion.toString(), row, column);
                        }

                        dtde.dropComplete(true);
                    }
                } catch (Exception e) {
                    SoapUI.logError(e);
                }
            }
        }

        public void dropActionChanged(DropTargetDragEvent dtde) {
        }

        public boolean isAcceptable(Transferable transferable, Point point) {
            int row = getPropertiesTable().rowAtPoint(point);
            if (row >= 0) {
                int column = getPropertiesTable().columnAtPoint(point);
                if (column != 1) {
                    return false;
                }

                if (!getPropertiesTable().isCellEditable(row, column)) {
                    return false;
                }
            } else if (!(getHolder() instanceof MutableTestPropertyHolder)) {
                return false;
            }

            DataFlavor[] flavors = transferable.getTransferDataFlavors();
            for (int i = 0; i < flavors.length; i++) {
                DataFlavor flavor = flavors[i];
                if (flavor.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType)) {
                    try {
                        Object modelItem = transferable.getTransferData(flavor);
                        if (modelItem instanceof PropertyModelItem
                                && ((PropertyModelItem) modelItem).getProperty().getModelItem() != getHolder()
                                .getModelItem()) {
                            return PropertyExpansionUtils.canExpandProperty(getHolder().getModelItem(),
                                    ((PropertyModelItem) modelItem).getProperty());
                        }
                    } catch (Exception ex) {
                        SoapUI.logError(ex);
                    }
                }
            }

            return false;
        }
    }

    /**
     * Idea is that all values which property name starts or ends with 'password'
     * case insesitive be shadowed.
     * This cell render in applied only on property value column.
     *
     * @author robert
     */
    protected static class PropertiesTableCellRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                                                       int row, int column) {
            Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (value instanceof String) {
                if (((String) value).length() > 0) {
                    String val = ((String) table.getValueAt(row, 0)).toLowerCase();
                    if (val.startsWith("password") || val.endsWith("password")) {
                        component = super.getTableCellRendererComponent(table, "**************", isSelected, hasFocus, row,
                                column);
                    }
                }
            }

            return component;
        }
    }

    public EnvironmentListener getEnvironmentListener() {
        return environmentListener;
    }

    public void setEnvironmentListener(EnvironmentListener environmentListener) {
        this.environmentListener = environmentListener;
    }

    public void interfaceAdded(Interface iface) {
    }

    public void interfaceRemoved(Interface iface) {
    }

    public void interfaceUpdated(Interface iface) {
    }

    public void testSuiteAdded(TestSuite testSuite) {
    }

    public void testSuiteRemoved(TestSuite testSuite) {
    }

    public void testSuiteMoved(TestSuite testSuite, int index, int offset) {
    }

    public void mockServiceAdded(MockService mockService) {
    }

    public void mockServiceRemoved(MockService mockService) {
    }

    public void afterLoad(Project project) {
    }

    public void beforeSave(Project project) {
    }

    public void environmentAdded(Environment env) {
    }

    public void environmentRemoved(Environment env, int index) {
    }

    public void environmentSwitched(Environment environment) {
    }

    public ProjectListenerAdapter getProjectListener() {
        return projectListener;
    }

    public void setProjectListener(ProjectListenerAdapter projectListener) {
        this.projectListener = projectListener;
    }
}
